package com.mk.transaction;

import lombok.extern.slf4j.Slf4j;

import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.function.Function;

/**
 * @Author makai
 * @Description: TODO
 * @Date 2024/4/10 17:48
 */
@Slf4j
@Service
public class SignInService {
    @Autowired
    private SignInCmdExe signInCmdExe;
    @Autowired
    RocketMQTemplate rocketMQTemplate;
    /** 签到 */
    public boolean doSignIn(String customerNo){
        // 查询当天签到积分 这里模拟当天积分是100
        long point=100;
        // 构建签到增加积分
        SignInMsgDTO signInMsgDTO = new SignInMsgDTO(customerNo,"20230401",point);
        // 构建消息体
        // 这里有两种方法可以选择
        // 1：自己生成事务ID写入消息体中这种方式要注意生成事务ID重复问题
        // 2：交由RocketMQ服务端自动生成我们在executeLocalTransaction方法中直接获取即可
//        String transactionId = UUID.randomUUID().toString();
//        Message<SignInMsgDTO> message = MessageBuilder.withPayload(signInMsgDTO).setHeader(RocketMQHeaders.TRANSACTION_ID,transactionId).build();
        Message<SignInMsgDTO> message = MessageBuilder.withPayload(signInMsgDTO).build();
        // 构建事务消息第三个参数，这里以Function函数为例 可以解决事务消息id回传问题，也可以自定义一个事务id写入消息体中
        Function function = new Function<String,Boolean>(){
            @Override
            public Boolean apply(String transactionId) {
                boolean execute = signInCmdExe.execute(customerNo, transactionId);
                return execute;
            }
        };
        // 发送事务消息:采用的是sendMessageInTransaction方法，返回结果为TransactionSendResult对象，该对象中包含了事务发送的状态、本地事务执行的状态等
        TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction("test-transaction-topic", message,function);
        // 事务消息提交状态
        String localTransactionState = result.getLocalTransactionState().name();
        // 如果消息被回滚代表业务执行异常本地事务提交失败
        if (LocalTransactionState.ROLLBACK_MESSAGE.name().equals(localTransactionState)) {
            log.info("发送事务消息失败 transactionId={} localTransactionState={} ", result.getTransactionId(), localTransactionState);
            return false;
        }
        log.info("发送事务消息成功 transactionId={} localTransactionState={} ", result.getTransactionId(), localTransactionState);
        return true;
    }
}
